
(function() {

    function MyXmlHttpRequest() {
        this._listeners = [];
    }
    
    MyXmlHttpRequest.UNSENT            = 0;
    MyXmlHttpRequest.OPENED            = 1;
    MyXmlHttpRequest.HEADERS_RECEIVED  = 2;
    MyXmlHttpRequest.LOADING           = 3;
    MyXmlHttpRequest.DONE              = 4;

    // Interface level constants
    MyXmlHttpRequest.prototype.UNSENT            = MyXmlHttpRequest.UNSENT;
    MyXmlHttpRequest.prototype.OPENED            = MyXmlHttpRequest.OPENED;
    MyXmlHttpRequest.prototype.HEADERS_RECEIVED  = MyXmlHttpRequest.HEADERS_RECEIVED;
    MyXmlHttpRequest.prototype.LOADING           = MyXmlHttpRequest.LOADING;
    MyXmlHttpRequest.prototype.DONE              = MyXmlHttpRequest.DONE;

    // Public Properties
    MyXmlHttpRequest.prototype.readyState    = MyXmlHttpRequest.UNSENT;
    MyXmlHttpRequest.prototype.responseText  = '';
    MyXmlHttpRequest.prototype.responseXML   = null;
    MyXmlHttpRequest.prototype.status        = 0;
    MyXmlHttpRequest.prototype.statusText    = '';

    // Priority proposal
    MyXmlHttpRequest.prototype.priority    = "NORMAL";

    MyXmlHttpRequest.prototype.method = '';
    MyXmlHttpRequest.prototype.url = '';
    MyXmlHttpRequest.prototype.async = true;
    MyXmlHttpRequest.prototype.user = '';
    MyXmlHttpRequest.prototype.password = '';

    // Instance-level Events Handlers
    MyXmlHttpRequest.prototype.onreadystatechange  = null;

    // Class-level Events Handlers
    MyXmlHttpRequest.onreadystatechange  = null;
    MyXmlHttpRequest.onopen              = null;
    MyXmlHttpRequest.onsend              = null;
    MyXmlHttpRequest.onabort             = null;
    MyXmlHttpRequest.onload              = null;
    MyXmlHttpRequest.onerror             = null;

    // Public Methods
    MyXmlHttpRequest.prototype.open  = function(sMethod, sUrl, bAsync, sUser, sPassword) {
        // http://www.w3.org/TR/XMLHttpRequest/#the-open-method
        var sLowerCaseMethod = sMethod.toLowerCase();
        if (sLowerCaseMethod == "connect" || sLowerCaseMethod == "trace" || sLowerCaseMethod == "track") {
            throw new Error(18);
        }

        delete this._headers;

        this.method   = sMethod;
        this.url      = sUrl;
        this.async    = bAsync;
        this.user     = sUser;
        this.password = sPassword;

        if (MyXmlHttpRequest.onopen) {
            MyXmlHttpRequest.onopen.apply(this, arguments);
        }

        this.readyState = MyXmlHttpRequest.OPENED;
        fReadyStateChange(this);
    };

    MyXmlHttpRequest.prototype.send = function(vData) {
        // Add method sniffer
        if (MyXmlHttpRequest.onsend) {
            MyXmlHttpRequest.onsend.apply(this, arguments);
        }

        if (!arguments.length) {
            vData = null;
        }

        if (vData && vData.nodeType) {
            vData = window.XMLSerializer ? new window.XMLSerializer().serializeToString(vData) : vData.xml;
            if (!this._headers["Content-Type"]) {
                this.setRequestHeader("Content-Type", "application/xml");
            }
        }

        this._data = vData;

        fXMLHttpRequest_send(this);
    };

    MyXmlHttpRequest.prototype.abort = function() {
        if (MyXmlHttpRequest.onabort) {
            MyXmlHttpRequest.onabort.apply(this, arguments);
        }

        if (this.readyState > MyXmlHttpRequest.UNSENT) {
            this._aborted = true;
        }

        fCleanTransport(this);

        this.readyState = MyXmlHttpRequest.UNSENT;
        delete this._data;
    };

    MyXmlHttpRequest.prototype.getAllResponseHeaders = function() {
        return null;
    };

    MyXmlHttpRequest.prototype.getResponseHeader = function(sName) {
        return null;
    };

    MyXmlHttpRequest.prototype.setRequestHeader  = function(sName, sValue) {
        if (!this._headers) {
            this._headers = {};
        }

        this._headers[sName]  = sValue;
    };

    MyXmlHttpRequest.prototype.addEventListener  = function(sName, fHandler, bUseCapture) {
        for (var nIndex = 0, oListener; oListener = this._listeners[nIndex]; nIndex++) {
            if (oListener[0] == sName && oListener[1] == fHandler && oListener[2] == bUseCapture) {
                return;
            }
        }

        // Add listener
        this._listeners.push([sName, fHandler, bUseCapture]);
    };

    MyXmlHttpRequest.prototype.removeEventListener = function(sName, fHandler, bUseCapture) {
        for (var nIndex = 0, oListener; oListener = this._listeners[nIndex]; nIndex++) {
            if (oListener[0] == sName && oListener[1] == fHandler && oListener[2] == bUseCapture) {
                break;
            }
        }

        // Remove listener
        if (oListener) {
            this._listeners.splice(nIndex, 1);
        }
    };

    MyXmlHttpRequest.prototype.dispatchEvent = function(oEvent) {
        var oEventPseudo  = {
            'type':             oEvent.type,
            'target':           this,
            'currentTarget':    this,
            'eventPhase':       2,
            'bubbles':          oEvent.bubbles,
            'cancelable':       oEvent.cancelable,
            'timeStamp':        oEvent.timeStamp,
            'stopPropagation':  function() {},  // There is no flow
            'preventDefault':   function() {},  // There is no default action
            'initEvent':        function() {}   // Original event object should be initialized
        };

        // Execute onreadystatechange
        if (oEventPseudo.type == "readystatechange" && this.onreadystatechange) {
            (this.onreadystatechange.handleEvent || this.onreadystatechange).apply(this, [oEventPseudo]);
        }


        // Execute listeners
        for (var nIndex = 0, oListener; oListener = this._listeners[nIndex]; nIndex++) {
            if (oListener[0] == oEventPseudo.type && !oListener[2]) {
                (oListener[1].handleEvent || oListener[1]).apply(this, [oEventPseudo]);
            }
        }

    };

    MyXmlHttpRequest.prototype.toString  = function() {
        return '[' + "object" + ' ' + "MyXmlHttpRequest" + ']';
    };

    MyXmlHttpRequest.toString  = function() {
        return '[' + "MyXmlHttpRequest" + ']';
    };

    MyXmlHttpRequest.prototype.fChangeValues = function(responseText, responseXML, status, statusText) {
        this.responseText = responseText;
        this.responseXML  = responseXML;
        this.status       = status;
        this.statusText   = statusText;
    }

    // Helper function
    function fXMLHttpRequest_send(oRequest) {
        oRequest.readyState = MyXmlHttpRequest.OPENED;
        plus.io.resolveLocalFileSystemURL(oRequest.url, function(entry) {
            entry.file( function(file) {
                console.log("getFile: " + JSON.stringify(file));

                var fileReader = new plus.io.FileReader();
                fileReader.readAsText(file, 'utf-8');
                fileReader.onloadend = function(evt) {
                    //console.log("evt.target.result: " + evt.target.result);
                    
                    oRequest.readyState = 4;
                    var responseText = evt.target.result;
                    var parser = new DOMParser();
                    var responseXML = parser.parseFromString(responseText, 'text/xml');
                    //console.log('responseText: ' + responseText);
                    oRequest.fChangeValues(responseText, responseXML, 200, 'success');
                    if (oRequest.onload) {
                        console.log('xmlhttprequest callback onload');
                        oRequest.onload();
                    }
                    fReadyStateChange(oRequest);
                }
            });
            
        }, function (e) {
            console.log("Resolve file URL failed: " + e.message);
            
            oRequest.readyState = 4;
            oRequest.fChangeValues('', null, 404, 'error');

            if (oRequest.onerror) {
                console.log('xmlhttprequest callback onerror');
                oRequest.onerror();
            }

            fReadyStateChange(oRequest);
        }); 
    }

    function fReadyStateChange(oRequest) {
        // Sniffing code
        if (MyXmlHttpRequest.onreadystatechange){
            MyXmlHttpRequest.onreadystatechange.apply(oRequest);
        }

        // Fake event
        oRequest.dispatchEvent({
            'type':       "readystatechange",
            'bubbles':    false,
            'cancelable': false,
            'timeStamp':  new Date().getTime()
        });
    }

    function fCleanTransport(oRequest) {
        //
    }

    if (!window.Function.prototype.apply) {
        window.Function.prototype.apply = function(oRequest, oArguments) {
            if (!oArguments) {
                oArguments  = [];
            }
            oRequest.__func = this;
            oRequest.__func(oArguments[0], oArguments[1], oArguments[2], oArguments[3], oArguments[4]);
            delete oRequest.__func;
        };
    }

    window.MyXmlHttpRequest = MyXmlHttpRequest;

})();